package com.marco.ipdata.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.marco.ipdata.domain.IPBase;
import com.marco.ipdata.domain.RequestContentDTO;
import com.marco.system.domain.ChinaAdInfo;
import com.marco.system.service.ChinaAdInfoService;
import com.marco.system.service.NormalizationService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * AbstractApiService.java
 * Create on 2017/3/22
 * Copyright(c) JD Inc 2017. All Rights Reserved.
 * <pre>
 * 功能说明：处理请求外部 API的信息
 * </pre>
 */
public abstract class AbstractApiService {
    // 阻塞队列 用于汇总API返回结果的统一处理
    private LinkedBlockingQueue<RequestContentDTO> rsQueue = new LinkedBlockingQueue<RequestContentDTO>(20000);
    @Autowired
    private NormalizationService normalizationService;
    @Autowired
    private ChinaAdInfoService adInfoService;
    @Autowired
    private IPBaseService ipBaseService;

    /**
     * 解析get请求
     */
    public void invokeGet(Map<String, String> params) {
        String ip = "";
        try {
            URIBuilder builder = new URIBuilder(url());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.setParameter(entry.getKey(), entry.getValue());
                if (entry.getKey().equals("ip")) {
                    ip = entry.getValue();
                }
            }
            String rs = "";
            Integer code = 1;//请求正常返回
            try {
                rs = Request.Get(builder.build()).socketTimeout(3000).connectTimeout(3000).execute().returnContent
                        ().asString();
            } catch (Exception e) {
                code = 2;//请求出现异常
            }
            RequestContentDTO dto = new RequestContentDTO.Builder(ip, code, rs, tags()).build();
            rsQueue.put(dto);
        } catch (Exception e) {
            getLogger().error("请求API {} 出现异常", tags(), e);
        }
    }

    /**
     * 处理存储在阻塞队列的调用返回结果,将处理好的数据存储到redis中
     */
    public void process() {
        Map<String, List<IPBase>> maps = Maps.newHashMap();
        try {
            while (true) {
                try {
                    if (CollectionUtils.isEmpty(rsQueue)) {
                        Thread.sleep(10000);
                        continue;
                    }
                    //处理阻塞队列
                    RequestContentDTO dto = rsQueue.poll();
                    //根据接口标志位存储数据
                    Map<String, String> rs = this.resolveResult(dto.getResult());
                    IPBase ipBase = normalizationService.formatAdStr(rs.get("ad"), adInfoService.getJdChinaMap());
                    if (ipBase == null) {
                        continue;
                    }
                    ipBase.setIp(dto.getIp());
                    ipBase.setIsp(rs.get("isp"));
                    ipBase.setSource(dto.getSource() + "");
                    ipBase.setUpdateDateTime(new Timestamp(DateTime.now().getMillis()));
                    String tableName = tableName();
                    ipBase.setTableName(tableName);
                    List<IPBase> list = maps.get(tableName) == null ? Lists.<IPBase>newArrayList() : maps.get(tableName);
                    list.add(ipBase);
                    if (list.size() > 100) {
                        ipBaseService.batchSave(tableName, list);
                        list.clear();
                    }
                    maps.put(tableName, list);
                } catch (Exception e) {
                    getLogger().error("处理接口返回数据出现异常", e);
                }
            }
        } catch (Exception e) {
            getLogger().error("处理阻塞队列出现异常，请检查");
        } finally {
            for (Map.Entry<String, List<IPBase>> entry : maps.entrySet()) {
                List<IPBase> list = entry.getValue();
                if (CollectionUtils.isNotEmpty(list)) {
                    ipBaseService.batchSave(entry.getKey(), list);
                }
            }
        }

    }

    public abstract void obtainApiDataByParam();

    /**
     * 处理接口返回的结果
     */
    protected abstract Map<String, String> resolveResult(String result);

    /**
     * 获取当前服务的日志记录器
     */
    protected abstract Logger getLogger();

    /**
     * 获取当前服务的请求链接
     */
    protected abstract String url();

    /**
     * 获取当前服务的表示位
     */
    protected abstract Integer tags();

    /**
     * 获取当前服务的存储表名
     */
    protected abstract String tableName();

}
